<?php

namespace App\Console\Commands\Test;

use App\Services\Bank\BankServiceManager;
use App\Services\Bank\BankServiceFactory;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class BankApiTestCommand extends Command
{
    protected $signature = 'bank:test {bank?} {operation?} {--data=*} {--file=}';

    protected $description = '银行API测试命令 (支持多银行)';

    private BankServiceManager $bankManager;

    public function __construct(BankServiceManager $bankManager)
    {
        parent::__construct();
        $this->bankManager = $bankManager;
    }

    public function handle()
    {
        // 为命令行执行设置日志上下文
        $logId = $this->generateLogId();
        Log::withContext(['log_id' => $logId]);

        $bankName = $this->argument('bank');
        $operation = $this->argument('operation');

        // 如果没有提供银行名称，则显示帮助
        if (!$bankName) {
            $this->showBankList();
            return 0;
        }

        // 如果没有提供操作，则显示操作列表
        if (!$operation) {
            $this->showOperationList($bankName);
            return 0;
        }

        // 获取银行服务
        try {
            $bankService = BankServiceFactory::make($bankName);
        } catch (\Exception $e) {
            $this->error("银行服务创建失败: {$e->getMessage()}");
            $this->showBankList();
            return 1;
        }

        $this->info("执行银行API测试: {$bankName} - {$operation}");
        $this->info("时间: " . now()->format('Y-m-d H:i:s'));
        $this->info("日志ID: {$logId}");
        $this->line('');

        switch ($operation) {
            case 'sync-bank':
                $this->testSyncBankNumbers($bankService);
                break;
            case 'query-bank':
                $this->testQueryBankNumbers($bankService);
                break;
            case 'query-balance':
                $this->testQueryBalance($bankService);
                break;
            case 'batch-pay':
                $this->testBatchPay($bankService);
                break;
            case 'query-pay':
                $this->testQueryPayResult($bankService);
                break;
            case 'apply-receipt':
                $this->testBatchApplyReceipt($bankService);
                break;
            case 'download-receipt':
                $this->testDownloadSingleReceipt($bankService);
                break;
            case 'query-daily':
                $this->testQueryDailyDetails($bankService);
                break;
            case 'query-history':
                $this->testQueryHistoryDetails($bankService);
                break;
            case 'all':
                $this->testAllOperations($bankService);
                break;
            default:
                $this->error("未知操作: {$operation}");
                $this->showUsage($bankName);
                return 1;
        }

        return 0;
    }

    private function testSyncBankNumbers($bankService)
    {
        $this->info('=== 测试联行号增量同步 ===');

        $queryDate = $this->option('data')[0] ?? Carbon::yesterday()->format('Y-m-d');
        $this->info("同步日期: {$queryDate}");

        $result = $bankService->syncBankNumbers($queryDate);
        $this->displayResult($result, $bankService);
    }

    private function testQueryBankNumbers($bankService)
    {
        $this->info('=== 测试联行号查询 ===');

        $data = $this->option('data');
        $bankName = $data[0] ?? '杭州银行股份有限公司上海北新泾支行';
        $bankTypeName = $data[1] ?? null;
        $isPreciseQuery = $data[2] ?? '1';

        $this->info("行名关键字: {$bankName}");
        if ($bankTypeName) {
            $this->info("行类型名称: {$bankTypeName}");
        }
        $this->info("查询类型: " . ($isPreciseQuery === '1' ? '精确查询' : '模糊查询'));

        $result = $bankService->queryBankNumbers($bankName, $bankTypeName, $isPreciseQuery);
        $this->displayResult($result, $bankService);
    }

    private function testQueryBalance($bankService)
    {
        $this->info('=== 测试余额查询 ===');

        $data = $this->option('data');
        $bankAcc = $data[0] ?? config('bank.banks.BankOfHangzhou.payer_acc_no');

        if (!$bankAcc) {
            $this->error('请提供银行账号或在配置中设置默认账号');
            return;
        }

        $this->info("查询账号: {$bankAcc}");

        try {
            $result = $bankService->queryBalance($bankAcc);
        } catch (\Throwable $e) {
            $this->error('余额查询失败: ' . $e->getMessage());
            return;
        }

        $this->line('');
        $this->info('=== 余额查询结果 ===');
        $this->info('账户可用余额: ' . ($result['available_balance'] ?? '未知'));
        $this->info('账户总余额: ' . ($result['balance'] ?? '未知'));
        $this->line('');
    }

    private function testBatchPay($bankService)
    {
        $this->info('=== 测试批量代发 ===');
        
        $erpBatchNo = 'TEST_BATCH_' . date('YmdHis');
        $wageTitle = '测试服务费发放';
        $busiType = '1'; // 工资
        
        // 测试数据
        $payDetails = [
            [
                'empNo' => 'EMP001',
                'userName' => '王五',
                'bankAcc' => '6222021001004789102',
                'amt' => '1000.00',
                'purpose' => '测试服务费',
                'payeeAccNo' => '6222021001004789102',
                'payeeName' => '王五',
                'amount' => '1000.00',
                'remark' => '测试服务费',
            ],
        ];
        
        // 验证明细数据
        $validation = $bankService->validatePayDetails($payDetails);
        if (!$validation['valid']) {
            $this->error('明细数据验证失败:');
            foreach ($validation['errors'] as $error) {
                $this->error("- {$error}");
            }
            return;
        }
        
        $this->info("ERP批次号: {$erpBatchNo}");
        $this->info("发放标题: {$wageTitle}");
        $this->info("明细数量: " . count($payDetails));
        
        $result = $bankService->batchPay($erpBatchNo, $wageTitle, $busiType, $payDetails);
        $this->displayResult($result, $bankService);
    }

    private function testQueryPayResult($bankService)
    {
        $this->info('=== 测试代发结果查询 ===');
        
        $data = $this->option('data');
        $erpBatchNo = $data[0] ?? null;
        $startDate = $data[1] ?? Carbon::yesterday()->format('Y-m-d');
        $endDate = $data[2] ?? Carbon::today()->format('Y-m-d');
        
        if ($erpBatchNo) {
            $this->info("ERP批次号: {$erpBatchNo}");
        } else {
            $this->info("查询日期范围: {$startDate} - {$endDate}");
        }
        
        $result = $bankService->queryPayResult($erpBatchNo, $startDate, $endDate);
        $this->displayResult($result, $bankService);
    }

    private function testBatchApplyReceipt($bankService)
    {
        $this->info('=== 测试回单批量申请 ===');

        $data = $this->option('data');

        $compFlowNo = $data[0] ?? ('TEST_FLOW_' . date('YmdHis'));
        $beginDate = $data[1] ?? Carbon::now()->subDay()->format('Y-m-d');
        $endDate = $data[2] ?? Carbon::now()->format('Y-m-d');

        $bankAccounts = array_slice($data, 3);
        if (empty($bankAccounts)) {
            $defaultAccount = config('bank.banks.BankOfHangzhou.payer_acc_no');
            if ($defaultAccount) {
                $bankAccounts[] = $defaultAccount;
            }
        }

        $this->info("业务批次号: {$compFlowNo}");
        $this->info("查询时间范围: {$beginDate} ~ {$endDate}");
        $this->info('银行卡号: ' . implode(', ', $bankAccounts));

        $result = $bankService->batchApplyReceipt($compFlowNo, $beginDate, $endDate, $bankAccounts);
        $this->displayResult($result, $bankService);
    }

    private function testDownloadSingleReceipt($bankService)
    {
        $this->info('=== 测试单笔回单下载 ===');

        $receiptNo = $this->option('data')[0] ?? 'RECEIPT001';
        $this->info("回单号: {$receiptNo}");

        $result = $bankService->downloadSingleReceipt($receiptNo);
        $this->displayResult($result, $bankService);
    }

    private function testQueryDailyDetails($bankService)
    {
        $this->info('=== 测试当日明细查询 ===');

        $data = $this->option('data');
        $bankAcc = $data[0] ?? '12331385690948598';
        $queryAmtBegin = isset($data[1]) && !empty($data[1]) ? floatval($data[1]) : null;
        $queryAmtEnd = isset($data[2]) && !empty($data[2]) ? floatval($data[2]) : null;
        $queryCdSign = $data[3] ?? null;
        $expandFields = $data[4] ?? 'serialNo';

        $this->info("查询账号: {$bankAcc}");
        if ($queryAmtBegin !== null) {
            $this->info("金额范围起: {$queryAmtBegin}");
        }
        if ($queryAmtEnd !== null) {
            $this->info("金额范围止: {$queryAmtEnd}");
        }
        if ($queryCdSign !== null) {
            $this->info("收支方向: " . ($queryCdSign === '0' ? '收入' : '支出'));
        }
        if ($expandFields !== null) {
            $this->info("额外字段: {$expandFields}");
        }

        $result = $bankService->queryDailyDetails($bankAcc, $queryAmtBegin, $queryAmtEnd, $queryCdSign, $expandFields);
        $this->displayResult($result, $bankService);
    }

    private function testQueryHistoryDetails($bankService)
    {
        $this->info('=== 测试历史明细查询 ===');

        $data = $this->option('data');
        $bankAcc = $data[0] ?? '3301040160019234205';
        $queryDateBegin = $data[1] ?? Carbon::yesterday()->format('Y-m-d');
        $queryDateEnd = $data[2] ?? Carbon::today()->subDay()->format('Y-m-d');
        $queryAmtBegin = isset($data[3]) && !empty($data[3]) ? floatval($data[3]) : null;
        $queryAmtEnd = isset($data[4]) && !empty($data[4]) ? floatval($data[4]) : null;
        $queryCdSign = $data[5] ?? null;
        $expandFields = $data[6] ?? 'serialNo';

        $this->info("查询账号: {$bankAcc}");
        $this->info("查询日期范围: {$queryDateBegin} - {$queryDateEnd}");
        if ($queryAmtBegin !== null) {
            $this->info("金额范围起: {$queryAmtBegin}");
        }
        if ($queryAmtEnd !== null) {
            $this->info("金额范围止: {$queryAmtEnd}");
        }
        if ($queryCdSign !== null) {
            $this->info("收支方向: " . ($queryCdSign === '0' ? '收入' : '支出'));
        }
        if ($expandFields !== null) {
            $this->info("额外字段: {$expandFields}");
        }

        $result = $bankService->queryHistoryDetails($bankAcc, $queryDateBegin, $queryDateEnd, $queryAmtBegin, $queryAmtEnd, $queryCdSign, $expandFields);
        $this->displayResult($result, $bankService);
    }

    private function testAllOperations($bankService)
    {
        $this->info('=== 执行所有接口测试 ===');
        $this->line('');

        // 测试联行号查询（相对安全）
        $this->testQueryBankNumbers($bankService);
        $this->line('');

        // 测试联行号同步
        $this->testSyncBankNumbers($bankService);
        $this->line('');

        // 测试当日明细查询
        $this->testQueryDailyDetails($bankService);
        $this->line('');

        // 测试历史明细查询
        $this->testQueryHistoryDetails($bankService);
        $this->line('');

        // 测试代发结果查询
        $this->testQueryPayResult($bankService);
        $this->line('');

        $this->warn('注意: 批量代发等涉及资金操作的接口需要谨慎测试');
    }

    private function displayResult(array $result, $bankService = null)
    {
        $this->line('');
        $this->info('=== 响应结果 ===');
        
        $status = $result['success'] ? '成功' : '失败';
        $this->info("状态: {$status}");
        $this->info("返回码: {$result['ret_code']}");
        $this->info("返回信息: {$result['ret_msg']}");
        
        if (!empty($result['map_data'])) {
            $this->info('Map数据:');
            foreach ($result['map_data'] as $key => $value) {
                $this->line("  {$key}: {$value}");
            }
        }
        
        if (!empty($result['loop_data'])) {
            $this->info('Loop数据 (' . count($result['loop_data']) . '条):');
            foreach (array_slice($result['loop_data'], 0, 5) as $index => $row) {
                $this->line("  [{$index}]:");
                foreach ($row as $key => $value) {
                    $this->line("    {$key}: {$value}");
                }
                $this->line('');
            }
            
            if (count($result['loop_data']) > 5) {
                $this->warn('... 仅显示前5条，共 ' . count($result['loop_data']) . ' 条数据');
            }
        }
        
        // 显示支付状态（如果适用）
        if (isset($result['ret_code']) && $bankService) {
            $paymentStatus = $bankService->getPaymentStatus($result);
            $statusMap = [
                'success' => '成功',
                'failed' => '失败',
                'pending' => '处理中',
                'suspicious' => '存疑',
            ];
            $this->info("调用状态: " . ($statusMap[$paymentStatus] ?? $paymentStatus));
        }
        
        $this->line('');
    }

    private function showBankList()
    {
        $this->line('');
        $this->info('可用银行列表:');
        $banks = BankServiceFactory::getAvailableBanks();
        foreach ($banks as $bank) {
            $this->line("  {$bank}");
        }
        $this->line('');
        $this->info('使用方法:');
        $this->line('  php artisan bank:test [银行名称] [操作]');
        $this->line('  例如: php artisan bank:test BankOfHangzhou query-daily');
        $this->line('');
    }

    private function showOperationList($bankName)
    {
        $this->line('');
        $this->info("可用操作列表 ({$bankName}):");
        $this->line('  sync-bank         - 联行号增量同步');
        $this->line('  query-bank        - 联行号查询');
        $this->line('  query-balance     - 余额查询');
        $this->line('  batch-pay         - 批量代发');
        $this->line('  query-pay         - 代发结果查询');
        $this->line('  apply-receipt     - 回单批量申请');
        $this->line('  download-receipt  - 单笔回单下载');
        $this->line('  query-daily       - 当日明细查询');
        $this->line('  query-history     - 历史明细查询');
        $this->line('  all               - 执行所有接口测试');
        $this->line('');
        $this->info('使用方法:');
        $this->line("  php artisan bank:test {$bankName} sync-bank [--data=2024-01-15]");
        $this->line("  php artisan bank:test {$bankName} query-bank [--data=工商银行 --data=蛇口]");
        $this->line("  php artisan bank:test {$bankName} batch-pay");
        $this->line("  php artisan bank:test {$bankName} query-pay [--data=BATCH001]");
        $this->line("  php artisan bank:test {$bankName} apply-receipt");
        $this->line("  php artisan bank:test {$bankName} download-receipt [--data=RECEIPT001]");
        $this->line("  php artisan bank:test {$bankName} query-daily [--data=账号 --data=金额起 --data=金额止 --data=收支方向 --data=额外字段]");
        $this->line("  php artisan bank:test {$bankName} query-history [--data=账号 --data=开始日期 --data=结束日期 --data=金额起 --data=金额止 --data=收支方向 --data=额外字段]");
        $this->line("  php artisan bank:test {$bankName} all");
        $this->line('');
        $this->info('参数说明:');
        $this->line('  query-daily: 账号 [金额起] [金额止] [收支方向] [额外字段]');
        $this->line('  query-history: 账号 开始日期 结束日期 [金额起] [金额止] [收支方向] [额外字段]');
        $this->line('  收支方向: 0-收入, 1-支出');
        $this->line('  额外字段: 以|分隔，如serialNo|voucherNo');
        $this->line('');
    }

    private function showUsage($bankName = null)
    {
        if ($bankName) {
            $this->showOperationList($bankName);
        } else {
            $this->showBankList();
        }
    }
    
    /**
     * 生成日志ID
     *
     * @return string
     */
    private function generateLogId(): string
    {
        return (string) mt_rand(100000000, 999999999);
    }
}
